package dbfactroy

import (
	"container/list"
	"encoding/json"
	"fmt"
	"gitee.com/cristiane/micro-mall-api/pkg/util/email"
	utils "gitee.com/ichub/goconfig/common/base/baseutils/stringutils"
	"gitee.com/ichub/gofactroy/common/dbcontent"
	"gitee.com/ichub/gofactroy/common/ichubbase"
	"github.com/jinzhu/gorm"
	"log"
	"os"
	"strings"
)

type DirFileContent struct {
	Dir, File, Content string //目录， 文件， 内容
}

type DbFactroy struct {
	Author       string //作者
	Dbtype_mysql bool
	Db           string  //数据库名
	Table        string  //表名
	TableComment *string //ModelNameWithTable bool

	Pkey       string
	PkeyType   string
	ModuleName ichubbase.ModuleDefine
	Tables     []string //genTables list

	GenDir     string
	GenDirTest string
	// tmp member var
	TestFiles       []string `json:"-"`
	StringFieldName string   `json:"-"`
	StringFieldLen  string   `json:"-"`

	AllTables []Tables         `json:"-"` //genTables all for CheckTableExist
	Dfcs      []DirFileContent `json:"-"` //dir service content

	DBUrl string
	I     int `json:"-"`
}

func (tool *DbFactroy) IniAll() (dbinst *gorm.DB) {
	InitMap(tool.Dbtype_mysql)
	dbinst = tool.InitDb(tool.DBUrl)
	ReCreateDirs()
	tool.IniLog()
	return
}
func (tool *DbFactroy) IniLog() *DbFactroy {
	logFile, err := os.OpenFile("./test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		fmt.Println("open log service failed, err:", err)
		return tool
	}
	log.SetOutput(logFile)
	return tool
}

func (tool *DbFactroy) InitDb(conn string) (dbinst *gorm.DB) {

	if tool.Dbtype_mysql {
		InitPathMysql()
		dbinst = dbcontent.InitDB_mysql(conn)
	} else {
		//filefactroy.init()
		dbinst = dbcontent.InitDB_pg(conn)
	}
	return
}

func (tool *DbFactroy) SendEmail(subj, msg string) {
	emailReq := &email.SendRequest{
		Receivers: []string{"leijmdas_s180@163.com"},
		Subject:   subj,
		Message:   msg,
	}
	email.DefaultEmailHelper = &email.Client{}
	// retry send email
	err := email.DefaultEmailHelper.SendEmail(emailReq)
	if err != nil {
		fmt.Println(err.Error()) // panic(err.Error())
	}
}

func (tool *DbFactroy) makeBase(structName string) string {
	s := `type %sBase struct{
}`
	return fmt.Sprintf(s, structName)
}

func (tool *DbFactroy) printList(lst *list.List) {
	fmt.Println("\n")
	for i := lst.Front(); i != nil; i = i.Next() {
		fmt.Println(i.Value)
	}
}

func (tool *DbFactroy) Println() {
	fmt.Println(tool.ToString())
}

func (tool *DbFactroy) findPGTableComment() *Tables {
	sql := `SELECT 
		relname as table_name,
		obj_description(oid) as table_comment
		FROM pg_class
		WHERE relkind = 'r' and relname='%s'
	`
	sql = fmt.Sprintf(sql, tool.Table)
	var tinfo Tables
	e := dbcontent.GetDB().Model(&PkInfo{}).Raw(sql).Find(&tinfo).Error
	if e != nil {
		fmt.Println("***=" + e.Error())

	}
	return &tinfo
}

func (tool *DbFactroy) findPGColumnComment() []COLUMNS {
	s := `SELECT 
    c.relname as TableName,
    col_description ( a.attrelid, a.attnum ) AS COLUMN_COMMENT,
    format_type ( a.atttypid, a.atttypmod ) AS COLUMN_TYPE,
    a.attname AS COLUMN_NAME 
	FROM pg_class AS c,    pg_attribute AS a
	WHERE    a.attrelid = c.oid   AND a.attnum >0
 			and c.relname = '%s'  `
	s = fmt.Sprintf(s, tool.Table)
	var cs []COLUMNS
	e := dbcontent.GetDB().Model(&PkInfo{}).Raw(s).Find(&cs).Error
	if e != nil {
		fmt.Println("***=" + e.Error())
	}

	return cs
}

func (tool *DbFactroy) BuildInfo(gendir string) {
	fmt.Println("=================================")
	fmt.Println(tool.ToString())
	log.Println(tool.ToString())
	tool.GenDir = gendir

	fmt.Println("你产生的代码路径在：" + tool.GenDir)

	fmt.Println("=================================")
	fmt.Println()

}

func (tool *DbFactroy) BuildInfoTest(gendir string) {
	fmt.Println("=================================")

	tool.GenDirTest = gendir

	fmt.Println("你产生的测试代码路径在：" + tool.GenDirTest)
	fmt.Println("=================================")
	log.Println(tool.TestFiles)
	fmt.Println(strings.Join(tool.TestFiles, ","))
	fmt.Println()

}

func (tmp *DbFactroy) String() string {
	s, _ := json.Marshal(tmp)
	return string(s)

}

func (tmp *DbFactroy) ToString() string {
	s, _ := json.MarshalIndent(tmp, "", "    ")
	return string(s)

}

type Tables struct {
	TableSchema  string `gorm:"column:table_schema"`
	TableName    string `gorm:"column:table_name"`
	TableComment string `gorm:"column:table_comment"`
}

func (tables *Tables) ToString() string {
	s, _ := json.Marshal(tables)
	return string(s)

}

// for postgres
type PkInfo struct {
	Pkname   string `gorm:"column:pkname"`
	Colname  string `gorm:"column:colname"`
	Typename string `gorm:"column:typename"`
}

func (pkInfo *PkInfo) String() string {
	s, _ := json.Marshal(pkInfo)
	return string(s)
}

func (pkInfo *PkInfo) ToString() string {
	s, _ := json.MarshalIndent(pkInfo, "", "    ")
	return string(s)
}

type COLUMNS struct {
	TableName      string `gorm:"column:table_name"`
	TableSchema    string `gorm:"column:table_schema"`
	COLUMN_NAME    string `gorm:"column:column_name"`
	DATA_TYPE      string `gorm:"column:data_type"`
	COLUMN_TYPE    string `gorm:"column:column_type"`
	COLUMN_KEY     string `gorm:"column:column_key"`
	CharMaxLen     string `gorm:"column:char_max_len"`
	COLUMN_COMMENT string `gorm:"column:column_comment"`
	COLUMN_DEFAULT string `gorm:"column:column_default"`
}

func (this *COLUMNS) String() string {
	s, _ := json.Marshal(this)
	return string(s)
}
func (this *COLUMNS) ToString() string {
	s, _ := json.MarshalIndent(this, "", "    ")
	return string(s)
}
func (this *COLUMNS) IfString() bool {
	return this.FindGoType(this.DATA_TYPE) == "string"
}

func (this *COLUMNS) ReturnValue() (ReturnValue string) {
	ReturnValue = ""
	if this.IfInt() || this.IfNumeric() {
		ReturnValue = "return 0"
	} else if this.IfBool() || this.IfBitField() {
		ReturnValue = "return false"
	} else if this.IfString() {
		ReturnValue = `return ""`
	} else if this.IfTime() {
		ReturnValue = `return time.Time{}`
	} else if this.IfLocalTimeInt() {
		ReturnValue = `return model.LocalTimeInt{}`
	} else if this.IfLocalTimeUTCInt() {
		ReturnValue = `return model.LocalTimeUTCInt{}`
	} else if this.IfLocalDateInt() {
		ReturnValue = `return model.LocalDateInt{}`
	} else if this.IfLocalTime() {
		ReturnValue = `return model.LocalTime {}`
	} else if this.IfLocalDate() {
		ReturnValue = `return model.LocalDate {}`
	}
	return
}

func (this *COLUMNS) IfBool() bool {
	return this.FindGoType(this.DATA_TYPE) == "bool"
}

func (this *COLUMNS) IfBitField() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "BitField")
}

func (this *COLUMNS) IfInt() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "int")
}
func (this *COLUMNS) IfInt64() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "int64")
}
func (this *COLUMNS) IfNumeric() bool {
	return this.IfInt() || strings.Contains(this.FindGoType(this.DATA_TYPE), "decimal") || strings.Contains(this.FindGoType(this.DATA_TYPE), "numeric") || strings.Contains(this.FindGoType(this.DATA_TYPE), "float")

}

func (this *COLUMNS) IfTime() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "time.Time")
}

func (this *COLUMNS) IfLocalTimeInt() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "model.LocalTimeInt")
}
func (this *COLUMNS) IfLocalTimeUTCInt() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "model.LocalTimeUTCInt")
}

func (this *COLUMNS) IfLocalDateInt() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "model.LocalDateInt")
}
func (this *COLUMNS) IfDate() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "date") || strings.Contains(
		this.FindGoType(this.DATA_TYPE), "Date")
}

func (this *COLUMNS) IfLocalTime() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "model.LocalTime")
}

func (this *COLUMNS) IfLocalDate() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "model.LocalDate")
}

func (this *COLUMNS) IfDateTime() bool {
	return strings.Contains(this.FindGoType(this.DATA_TYPE), "time")
}

/*double	double	double
float	float	float
int32	int	int32	使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数，那么请使用sint32。
int64	long	int64	使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数，那么请使用sint64。
unit32	int[1]	unit32	总是4个字节。如果数值总是比总是比228大的话，这个类型会比uint32高效。
unit64	long[1]	unit64	总是8个字节。如果数值总是比总是比256大的话，这个类型会比uint64高效。
sint32	int	int32	使用可变长编码方式。有符号的整型值。编码时比通常的int32高效。
sint64	long	int64	使用可变长编码方式。有符号的整型值。编码时比通常的int64高效。
fixed32	int[1]	unit32
fixed64	long[1]	unit64	总是8个字节。如果数值总是比总是比256大的话，这个类型会比uint64高效。
sfixed32	int	int32	总是4个字节。
sfixed64	long	int64	总是8个字节。
bool	boolean	bool
string	String	string	一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
bytes
*/

//dbcontent type->go type

func (tool *DbFactroy) makeModelColNewLst(columns *[]COLUMNS, ifnil bool) *list.List {

	s := `
	entity.{{.colname}} = new({{.goType}})
	`
	lst := list.New()
	for _, v := range *columns {
		colname := utils.Case2Camel(v.COLUMN_NAME)

		goType := v.FindGoType(v.DATA_TYPE)
		if v.COLUMN_NAME != tool.Pkey {
			vars := make(map[string]interface{})
			vars["goType"] = goType
			vars["colname"] = colname
			lst.PushBack(utils.ParseTemplateString(s, vars))
		}
	}
	tool.printList(lst)
	return lst
}

func (tool *DbFactroy) makeModelGo(columns *[]COLUMNS) *list.List {
	sn := fmt.Sprintf(utils.Case2Camel(tool.Table))
	snbase := tool.makeBase(sn)
	lst := list.New()
	lst.PushBack(("/* 指定扩展结结构，单独存文件。生成时不会覆盖: */"))

	lst.PushBack(fmt.Sprintf("//type %sBase struct {ModelBase}", sn))
	comment := fmt.Sprintf("/*  %s  */", *tool.TableComment)
	lst.PushBack(comment)

	lst.PushBack(fmt.Sprintf("type %s%s struct {", "", utils.UcfirstCase2Camel(tool.Table)))
	//lst.PushBack(fmt.Sprintf("\tmodel.ParamBase" ))
	lst.PushBack(fmt.Sprintf("//\t%sBase", sn))
	lst.PushBack(fmt.Sprintf("//\tModelBase"))

	for _, v := range *columns {
		col_comment := fmt.Sprintf("\t/*  %s  */", v.COLUMN_COMMENT)
		lst.PushBack(col_comment)
		//timeStr :=v.Birthday.Format("2006-01-02 15:04:05")
		dt := v.FindGoType(v.DATA_TYPE)

		col_def := v.COLUMN_NAME + ";type:" + v.COLUMN_TYPE
		if v.COLUMN_NAME == tool.Pkey {
			col_def = col_def + ";PRIMARY_KEY"
		}
		if tool.Dbtype_mysql {
			col_def = col_def + fmt.Sprintf(";comment:'%s'", v.COLUMN_COMMENT)
		}
		//if true || tool.Dbtype_mysql {
		if len(v.COLUMN_DEFAULT) > 0 {
			if v.IfNumeric() {
				col_def = col_def + fmt.Sprintf(";default:%s", v.COLUMN_DEFAULT)
			}
			if v.IfString() {
				col_def = col_def + fmt.Sprintf(";default:\\'%s\\'", v.COLUMN_DEFAULT)
			}
		}
		//}

		json_def := v.COLUMN_NAME //utils.Lcfirst(utils.Case2Camel(v.COLUMN_NAME))
		if dt == "int64" {        //&& v.COLUMN_NAME == DbFactroy.Pkey
			json_def = json_def + ",string"
		}
		lst.PushBack(fmt.Sprintf("\t%s *%s `gorm:\"column:%s\" json:\"%s\"`", utils.Case2Camel(v.COLUMN_NAME), dt, col_def, json_def))
	}
	lst.PushBack("}")

	fmt.Println(snbase)
	for i := lst.Front(); i != nil; i = i.Next() {
		fmt.Println(i.Value)
	}
	return lst
}
func (tool *DbFactroy) makeModelBodyGo(columns *[]COLUMNS) *list.List {

	lines := list.New()

	for _, c := range *columns {
		col_comment := fmt.Sprintf("\t/*  %s  */", c.COLUMN_COMMENT)
		lines.PushBack(col_comment)
		dt := c.FindGoType(c.DATA_TYPE)

		col_def := c.COLUMN_NAME + ";type:" + c.COLUMN_TYPE
		if c.COLUMN_NAME == tool.Pkey {
			col_def = col_def + ";PRIMARY_KEY"
		}
		if tool.Dbtype_mysql {
			col_def = col_def + fmt.Sprintf(";comment:'%s'", c.COLUMN_COMMENT)
		}
		//if true || tool.Dbtype_mysql {
		if len(c.COLUMN_DEFAULT) > 0 {
			if c.IfNumeric() {
				col_def = col_def + fmt.Sprintf(";default:%s", c.COLUMN_DEFAULT)
			}
			if c.IfString() {
				col_def = col_def + fmt.Sprintf(";default:\\'%s\\'", c.COLUMN_DEFAULT)
			}
		}
		json_def := c.COLUMN_NAME
		if tool.Dbtype_mysql {
			json_def = utils.Lcfirst(utils.Case2Camel(c.COLUMN_NAME))
		}
		if dt == "int64" { //&& c.COLUMN_NAME == DbFactroy.Pkey
			json_def = json_def + ",string"
		}
		lines.PushBack(fmt.Sprintf("\t%s %s `gorm:\"column:%s\" json:\"%s\"`", utils.Case2Camel(c.COLUMN_NAME), dt, col_def, json_def))
	}

	for i := lines.Front(); i != nil; i = i.Next() {
		log.Println(i.Value)
	}
	return lines
}

func (tool *DbFactroy) makeModelDtoGo(columns *[]COLUMNS) *list.List {

	lines := list.New()

	for _, c := range *columns {
		col_comment := fmt.Sprintf("\t/*  %s  */", c.COLUMN_COMMENT)
		lines.PushBack(col_comment)
		dt := c.FindGoType(c.DATA_TYPE)

		col_def := c.COLUMN_NAME + ";type:" + c.COLUMN_TYPE
		if c.COLUMN_NAME == tool.Pkey {
			col_def = col_def + ";PRIMARY_KEY"
		}
		if tool.Dbtype_mysql {
			col_def = col_def + fmt.Sprintf(";comment:'%s'", c.COLUMN_COMMENT)
		}
		//if true || tool.Dbtype_mysql {
		if len(c.COLUMN_DEFAULT) > 0 {
			if c.IfNumeric() {
				col_def = col_def + fmt.Sprintf(";default:%s", c.COLUMN_DEFAULT)
			}
			if c.IfString() {
				col_def = col_def + fmt.Sprintf(";default:\\'%s\\'", c.COLUMN_DEFAULT)
			}
		}
		json_def := c.COLUMN_NAME
		if tool.Dbtype_mysql {
			json_def = utils.Lcfirst(utils.Case2Camel(c.COLUMN_NAME))
		}
		if dt == "int64" { //&& c.COLUMN_NAME == DbFactroy.Pkey
			json_def = json_def + ",string"
		}
		if dt == "bool" {
			dt = "string"
			lines.PushBack(fmt.Sprintf("\t%s %s `gorm:\"column:%s\" json:\"%s\"`", utils.Case2Camel(c.COLUMN_NAME), dt, col_def, json_def))

		} else {
			lines.PushBack(fmt.Sprintf("\t%s %s `gorm:\"column:%s\" json:\"%s\"`", utils.Case2Camel(c.COLUMN_NAME), dt, col_def, json_def))
		}
	}

	for i := lines.Front(); i != nil; i = i.Next() {
		log.Println(i.Value)
	}
	return lines
}

func (tool *DbFactroy) BuildModel() (cs *[]COLUMNS, ms *list.List, ps *list.List, msdto *list.List) {

	cs = tool.FindCOLUMNS()
	ms = tool.makeModelBodyGo(cs)   // ms = DbFactroy.makeModelGo(cs)
	msdto = tool.makeModelDtoGo(cs) // ms = DbFactroy.makeModelGo(cs)
	ps = tool.MakeModelProtoBody(cs)

	return cs, ms, ps, msdto

}

func (tool *DbFactroy) MakeModelProto() *list.List {
	cs := tool.FindCOLUMNS()
	lst := tool.makeModelProto(cs)
	return lst

}
func (tool *DbFactroy) MakeModelProtoBody(columns *[]COLUMNS) *list.List {

	sn := fmt.Sprintf(utils.Case2Camel(tool.Table))
	snbase := tool.makeBase(sn)
	lst := list.New()
	i := 5
	for _, v := range *columns {
		log.Println(v.String())
		dt := tool.FindProtoType(v.DATA_TYPE)
		if dt == "" {
			dt = "string"
		}
		lst.PushBack(fmt.Sprintf("\t%s %s = %d;", dt, utils.Lcfirst(utils.Case2Camel(v.COLUMN_NAME)), i))
		i++
	}

	log.Println(snbase)
	for i := lst.Front(); i != nil; i = i.Next() {

		log.Println(i.Value)
	}
	return lst
}

func (tool *DbFactroy) makeModelProto(columns *[]COLUMNS) *list.List {
	sn := fmt.Sprintf(utils.Case2Camel(tool.Table))
	snbase := tool.makeBase(sn)
	lst := list.New()
	//lst.PushBack(fmt.Sprintf("type %s%s struct {", Capitalize(tmp.Db), Capitalize(tmp.Table)))
	lst.PushBack(fmt.Sprintf("message %sProto   {", utils.UcfirstCase2Camel(utils.Capitalize(tool.Table))))

	i := 1
	for _, v := range *columns {
		//timeStr :=cd v.Birthday.Format("2006-01-02 15:04:05")
		fmt.Println(v.String())
		dt := tool.FindProtoType(v.DATA_TYPE)
		if dt == "" {
			log.Println("")
			dt = "string"
		}
		lst.PushBack(fmt.Sprintf("\t%s %s = %d;", dt, utils.Case2Camel(v.COLUMN_NAME), i))
		i = i + 1
	}
	lst.PushBack("}")
	fmt.Println(snbase)
	fmt.Println("\n")
	for i := lst.Front(); i != nil; i = i.Next() {

		fmt.Println(i.Value)
	}
	return lst
}

func (tool *DbFactroy) FindPgPkey(table string) []PkInfo {
	s := `SELECT
	pg_constraint.conname AS pkname,
	pg_attribute.attname AS colname,
	pg_type.typname AS typename
		FROM pg_constraint
		INNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
		INNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid
		AND pg_attribute.attnum = pg_constraint.conkey [ 1 ]
		INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid
	WHERE	pg_class.relname = '%s'
		AND pg_constraint.contype = 'p' `

	var pkInfos []PkInfo
	s = fmt.Sprintf(s, table)
	log.Println("Find PKey: " + s)
	e := dbcontent.GetDB().Model(&PkInfo{}).Raw(s).Find(&pkInfos).Error
	if e != nil {
		fmt.Println(e.Error())
	}

	log.Println("FindPgPkey: \n" + s)
	if len(pkInfos) == 0 {
		fmt.Println(fmt.Sprintf("pkInfos len=0 无主键（可能表%s不存在！） ", table))
	}
	log.Println(fmt.Sprintf("pkInfos: %d", len(pkInfos)))
	return pkInfos
}

func (this *COLUMNS) FindGoType(fieldType string) (goType string) {

	return InstContext.FindGoType(fieldType)
}

func (tool *DbFactroy) buildIf(columns *[]COLUMNS) *list.List {
	lst := list.New()
	s := `
		if param.Param.%s != nil {
			dbc = dbc.Where("%s=?", *param.Param.%s)
		}`
	for _, v := range *columns {
		cc := utils.Case2Camel(v.COLUMN_NAME)
		//timeStr := v.Birthday.Format("2006-01-02 15:04:05")
		if v.IfString() {
			s = `
			if param.Param.%s != nil ||  *param.Param.%s != "" {
				dbc = dbc.Where("%s = ?", *param.Param.%s)
			}`
			s = fmt.Sprintf(s, cc, cc, v.COLUMN_NAME, cc)
		} else if v.IfNumeric() {
			s = `
			if param.Param.%s != nil  ||  *param.Param.%s != 0 {
				dbc = dbc.Where("%s=?", *param.Param.%s)
			}`
			s = fmt.Sprintf(s, cc, cc, v.COLUMN_NAME, cc)
		} else {
			s = `
			if param.Param.%s != nil {
				dbc = dbc.Where("%s=?", *param.Param.%s)
			}`
			s = fmt.Sprintf(s, cc, v.COLUMN_NAME, cc)
		}

		lst.PushBack(s)
	}
	return lst
}

func (tool *DbFactroy) FindCOLUMNS() *[]COLUMNS {

	var columns []COLUMNS
	var sql string
	if tool.Dbtype_mysql {
		sql = fmt.Sprintf(
			`select TABLE_NAME as table_name,
						 TABLE_SCHEMA as table_schema,
						 COLUMN_NAME  as column_name,
						 DATA_TYPE  as data_type,
						 COLUMN_TYPE  as column_type,  
						 COLUMN_KEY  as column_key ,
						 column_comment as column_comment ,
						 column_default as column_default 

					from information_schema.COLUMNS 
					where table_schema='%s' and table_name='%s'`, tool.Db, tool.Table)

	} else {
		//postgres sql
		sql = fmt.Sprintf(`select TABLE_NAME as table_name,
						 table_catalog as table_schema,
						 COLUMN_NAME  as column_name,
						 udt_name  as data_type,
						 crdb_sql_type  as column_type,  
						 character_maximum_length as char_max_len, 
						 ''  as column_key ,
						 column_default as column_default
						 from information_schema.COLUMNS 
						 where table_catalog ='%s' and table_name='%s'`, tool.Db, tool.Table)

	}
	log.Println(sql + "\n")
	e := dbcontent.GetDB().Raw(sql).Find(&columns).Error
	if e != nil {
		panic(e.Error())
	}

	if len(columns) == 0 {
		panic(tool.Table + " columns len =0 (表不存在！)")
	}

	if tool.Dbtype_mysql {
		for _, v := range columns { //timeStr := v.Birthday.Format("2006-01-02 15:04:05")

			if v.COLUMN_KEY == "PRI" || v.COLUMN_NAME == "id" {
				tool.Pkey = v.COLUMN_NAME
				tool.PkeyType = v.DATA_TYPE
			}
			if v.IfString() {
				tool.StringFieldName = v.COLUMN_NAME
				tool.StringFieldLen = v.CharMaxLen
			}
		}
	} else { // pgsql

		pks := tool.FindPgPkey(tool.Table)
		log.Println(fmt.Sprintf("pkInfos: %d", len(pks)))
		tool.Pkey = "id"
		tool.PkeyType = "int64"
		if len(pks) > 0 {
			tool.Pkey = pks[0].Colname
			tool.PkeyType = pks[0].Typename
		}

		cscomment := tool.findPGColumnComment()
		for index := range columns { //timeStr := v.Birthday.Format("2006-01-02 15:04:05")
			for _, c := range cscomment {
				if columns[index].COLUMN_NAME == c.COLUMN_NAME {
					columns[index].COLUMN_COMMENT = c.COLUMN_COMMENT

				}
			}
			if columns[index].IfString() {
				tool.StringFieldName = columns[index].COLUMN_NAME
				tool.StringFieldLen = columns[index].CharMaxLen
			}
		}

	}

	return &columns
}

func (tool *DbFactroy) FindTableComment() {
	if tool.Dbtype_mysql { //tool.TableComment == nil &&
		tbls := tool.FindTables()
		for _, v := range tbls {
			if tool.Table == v.TableName {
				tool.TableComment = &v.TableComment
				return
			}
		}
	}

	if !tool.Dbtype_mysql { //tool.TableComment == nil &&
		tc := tool.findPGTableComment()
		tool.TableComment = &tc.TableComment

	}

}

func (tool *DbFactroy) CheckTableExist() bool {
	if len(tool.AllTables) == 0 {
		tool.AllTables = tool.FindTables()
	}
	for _, table := range tool.AllTables {
		if table.TableName == tool.Table {
			return true
		}
	}
	return false
}

func (tool *DbFactroy) FindTables() []Tables {
	var tables []Tables
	if tool.Dbtype_mysql {
		sql := fmt.Sprintf(
			`select table_name as table_name ,
							 table_schema as table_schema ,
							 table_comment as table_comment
					 from information_schema.TABLES where table_schema='%s'  `, tool.Db)
		err := dbcontent.GetDB().Raw(sql).Find(&tables).Error
		if err != nil {
			panic(err.Error() + " :" + sql)

		}
	} else {
		sql := fmt.Sprintf(
			`SELECT table_name as table_name,
						table_catalog  as table_schema
						FROM INFORMATION_SCHEMA.tables 
						WHERE table_schema='public' AND table_type IN ('BASE TABLE','VIEW') `)
		err := dbcontent.GetDB().Raw(sql).Find(&tables).Error
		if err != nil {
			panic(err.Error() + " :" + sql)

		}

	}
	if len(tables) > 0 {
		log.Println(len(tables))
		//json.Marshal(tables)
	}
	return tables
}

func (tool *DbFactroy) FindGoType(fieldType string) (goType string) {

	goType = InstContext.FindGoType(fieldType)
	return
}

func (tool *DbFactroy) FindProtoType(fieldType string) (pbType string) {

	pbType = InstContext.FindProtoType(fieldType)
	return
}
